package org.aspectsense.middleware.scheduler;

/**
 * @author Nearchos Paspallis [nearchos@cs.ucy.ac.cy]
 *         Date: Feb 8, 2008
 *         Time: 10:16:32 AM
 */
public class Scheduler implements Runnable
{
    public static final long THREAD_INTERVAL = 100L; // in milliseconds

    private static Scheduler instance = null;
    private final ScheduledRunnables scheduledRunnables;

    private Scheduler()
    {
        scheduledRunnables = new ScheduledRunnables();
        new Thread(this).start();
    }
    
    static public Scheduler getInstance()
    {
        synchronized (Scheduler.class)
        {
            if(instance == null) instance = new Scheduler();

            return instance;
        }
    }

    public void run()
    {
        while(true)
        {
            final long currentTimeMillis = System.currentTimeMillis();
            final Runnable runnable
                    = scheduledRunnables.popNextRunnable(currentTimeMillis);

            if(runnable != null)
            {
                runnable.run();
            }
            else
            {
                try
                {
                    Thread.sleep(THREAD_INTERVAL);
                }
                catch (InterruptedException ie)
                {
                    System.err.println("Error! Scheduler terminated.\n" + this);
                    throw new RuntimeException(ie);
                }
            }
        }
    }


    /**
     * Schedules the specified event.
     *
     * @param event the event to be scheduled
     */
    synchronized public void scheduleEvent(final Event event)
    {
        if(event == null)
        {
            throw new NullPointerException("Illegal null argument");
        }
        scheduledRunnables.addScheduledEvent(event);
    }

    synchronized public void removeRecurringEvent(final RecurringEvent event)
    {
        if(event == null)
        {
            throw new NullPointerException("Illegal null argument");
        }

        scheduledRunnables.removeScheduledEvent(event);
    }

  
    public int getLoad()
    {
        return scheduledRunnables.getNumberOfScheduledRunnables();
    }

    public String toString()
    {
        return "Scheduler{THREAD_INTERVAL=" + THREAD_INTERVAL
                + ", schedule=" + scheduledRunnables + "}";
    }
}